package sk.ownage.p1.featurestore;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.StreamCorruptedException;

import android.util.Log;

import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.MarkerOptions;

public class LandmarkQuadTreeNode {
	final String TAG="LandmarkQuadTreeNode";
	int threshold=LandmarkQuadTreeRoot.actualThreshold;
	int DIRECTORY_MAX=LandmarkStore.DIRECTORY_MAX;
	public LatLngBounds boundingBox;
	public LandmarkQuadTreeNode northWest,northEast,southWest,southEast;
	public LatLng NW,SE,center;
	String path,exactpath;
	File landmarksListFile;
	String name;
	int size=0;
	boolean divided=false;
	boolean skip=false;
	
	public LandmarkQuadTreeNode(String _name, LatLngBounds bounding,String _path){
		boundingBox=bounding;
		name=_name;
		path=_path;
		exactpath=path+"/"+"list.bin";
		NW=new LatLng(boundingBox.northeast.latitude, boundingBox.southwest.longitude);
		SE=new LatLng( boundingBox.southwest.latitude, boundingBox.northeast.longitude);
		center=getCenter(boundingBox);

		size=loadSize();
		//ak do tejto vetvy este mozeme pridavat body
		if(!skip){
			File folder=new File(path);
			if(!folder.exists()){
				folder.mkdirs();
			}
			landmarksListFile=new File(exactpath);
			if(!landmarksListFile.exists()){
				try {
					FileOutputStream fos= new FileOutputStream(landmarksListFile);
					ObjectOutputStream os = new ObjectOutputStream(fos);
					os.close();
				} catch (FileNotFoundException e) {
					Log.e(TAG, e.toString());
					e.printStackTrace();
				} catch (IOException e) {
					Log.e(TAG, e.toString());
					e.printStackTrace();
				}
			}
		}
		//ak v skutocnosti uz existuju vetvy tejto vetvy
		else{
			northEast=new LandmarkQuadTreeNode(name+">NE", new LatLngBounds(center,boundingBox.northeast),path+"/0");
			northWest=new LandmarkQuadTreeNode(name+">NW", new LatLngBounds(new LatLng(center.latitude, boundingBox.southwest.longitude), new LatLng(boundingBox.northeast.latitude, center.longitude)),path+"/1");
			southEast=new LandmarkQuadTreeNode(name+">SE", new LatLngBounds(new LatLng(boundingBox.southwest.latitude, center.longitude), new LatLng(center.latitude,boundingBox.northeast.longitude)),path+"/2");
			southWest=new LandmarkQuadTreeNode(name+">SW", new LatLngBounds(boundingBox.southwest,center),path+"/3");
		}
	}
	
	
	
	private LatLng getCenter(LatLngBounds bbox){
		double averageLat=(bbox.northeast.latitude+bbox.southwest.latitude)/2;
		double averageLon=(bbox.northeast.longitude+bbox.southwest.longitude)/2;
		return new LatLng(averageLat, averageLon);
	}
	
	public void addMarkerOption(MarkerOptions input){
		if(!skip)
			size=loadSize();
		ObjectInputStream is;
		if(size<threshold && !divided){
			try {
				FileOutputStream fos = new FileOutputStream(landmarksListFile, true);
				AppendingObjectOutputStream os= new AppendingObjectOutputStream(new BufferedOutputStream(fos));
				os.writeDouble(input.getPosition().latitude);
				os.writeDouble(input.getPosition().longitude);
				os.writeUTF((input.getTitle()!=null)?input.getTitle():"");
				os.close();
			} catch (FileNotFoundException e) {
				Log.e(TAG, e.toString());
				e.printStackTrace();
			} catch (IOException e) {
				Log.e(TAG, e.toString());
				e.printStackTrace();
			}
			size++;
			saveSize();
		}
		else if(!divided){
			try {
				FileInputStream fis = new FileInputStream(landmarksListFile);
				is = new ObjectInputStream(new BufferedInputStream(fis));
				int count=size;
				while (count >0) {
					MarkerOptions tempMO=new MarkerOptions().position(new LatLng(is.readDouble(), is.readDouble())).title(is.readUTF());
					addMarkerOptionToSubTree(tempMO);
					count--;
				}
				is.close();
				addMarkerOptionToSubTree(input);
				landmarksListFile.delete();
			} catch (StreamCorruptedException e) {
				Log.e(TAG, e.toString());
				e.printStackTrace();
			} catch (IOException e) {
				Log.e(TAG, e.toString());
				e.printStackTrace();
			}
			divided=true;
			skip=true;
			saveSize();
		}
		else{
			addMarkerOptionToSubTree(input);
		}
	}
	
	private void addMarkerOptionToSubTree(MarkerOptions mo){
		if(mo.getPosition().latitude>=center.latitude){
			if(mo.getPosition().longitude>=center.longitude){
				if(northEast==null)
					northEast=new LandmarkQuadTreeNode(name+">NE", new LatLngBounds(center,boundingBox.northeast),path+"/0");
				northEast.addMarkerOption(mo);
			}
			else{
				if(northWest==null)
					northWest=new LandmarkQuadTreeNode(name+">NW", new LatLngBounds(new LatLng(center.latitude, boundingBox.southwest.longitude), new LatLng(boundingBox.northeast.latitude, center.longitude)),path+"/1");
				northWest.addMarkerOption(mo);
			}
		}
		else{
			if(mo.getPosition().longitude>=center.longitude){
				if(southEast==null)
					southEast=new LandmarkQuadTreeNode(name+">SE", new LatLngBounds(new LatLng(boundingBox.southwest.latitude, center.longitude), new LatLng(center.latitude,boundingBox.northeast.longitude)),path+"/2");
				southEast.addMarkerOption(mo);
			}
			else{
				if(southWest==null)
					southWest=new LandmarkQuadTreeNode(name+">SW", new LatLngBounds(boundingBox.southwest,center),path+"/3");
				southWest.addMarkerOption(mo);
			}
		}
	}
	
	private int loadSize(){
		File sizePath=new File(path+"/"+"size.bin");
		int result=0;
		if(sizePath.exists())
		try {
			FileInputStream fis = new FileInputStream(sizePath);
			ObjectInputStream is = new ObjectInputStream(fis);
			result=is.readInt();
			divided=is.readBoolean();
			skip=is.readBoolean();
			is.close();
		} catch (Exception e) {
			Log.d(TAG, e.toString());
		}
		return result;
	}
	
	public void saveSize(){
		File sizePath=new File(path+"/"+"size.bin");
		try {
			FileOutputStream fos = new FileOutputStream(sizePath);
			ObjectOutputStream os = new ObjectOutputStream(fos);
			os.writeInt(size);
			os.writeBoolean(divided);
			os.writeBoolean(skip);
			os.close();
		} catch (Exception e) {
			Log.d(TAG, e.toString());
		}
	}

}

